這邊是假設今天有個是要在玩家全部行動完畢時結束回合,而這邊會用Visitor獲取玩家單位的可行動數量+用Observer每次在控制狀態為等待輸入(CALWaitingForInputCellGridState)觸發更新
Unit.cs
public virtual void RunVisitor(IUnitVisitor unitVisitor) 
{ 
    unitVisitor.VisitUnit(this); 
}
UnitSystem.cs
using LinXuan.Common.Main; 
using LinXuan.Common.Misc; 
using LuLuBearStudio.Characters; 
using System.Collections.Generic; 
namespace LinXuan.TBSF.Misc 
{ 
    public class UnitSystem : IGameSystem 
    { 
        private CellGrid m_CellGrid; 
        private List<Unit> m_PlayerUnits = new List<Unit>(); 
        private List<Unit> m_EnemyUnits = new List<Unit>(); 
        private List<Unit> m_AllUnits = new List<Unit>(); 
        public List<Unit> PlayableUnit { get; private set; } 
        public UnitSystem(CellGrid cellGrid) 
        { 
            m_CellGrid = cellGrid; 
            Initialize(); 
        } 
        public void Initialize() 
        { 
        } 
        public void Initialize(List<Unit> units) 
        { 
            m_AllUnits = units; 
            m_PlayerUnits.AddRange(m_AllUnits.FindAll(u => u is IPlayer)); 
            m_EnemyUnits.AddRange(m_AllUnits.FindAll(u => u is IEnemy)); 
        } 
        public void RunVisitor(IUnitVisitor unitVisitor) 
        { 
            foreach (Unit unit in m_AllUnits) 
                unit.RunVisitor(unitVisitor); 
        } 
    } 
}
IUnitVisitor.cs
using LuLuBearStudio.Characters; 
namespace LinXuan.Common.Misc 
{ 
    public abstract class IUnitVisitor 
    { 
        public virtual void VisitUnit(Unit unit) 
        { 
        }
        public virtual void VisitPlayerUnit(IPlayer player) 
        { 
            VisitUnit(player); 
        }
        public virtual void VisitEnemyUnit(IEnemy enemy) 
        { 
            VisitUnit(enemy); 
        } 
    } 
}
UnitInfoVisitor.cs
using Assets.Scripts.GUI.GUITool; 
using LinXuan.Common.Misc; 
using LuLuBearStudio.CALAbilities; 
using LuLuBearStudio.Characters; 
namespace LinXuan.TBSF.Misc 
{ 
    public class UnitInfoVisitor : IUnitVisitor 
    { 
        public int UnitCount { get; private set; } 
        public int PlayerCount { get; private set; } 
        public int EnemyCount { get; private set; } 
        public int UseableUnitCount { get; private set; } 
        public int MovableUnitCount { get; private set; } 
        public int AttackableUnitCount { get; private set; }
        public override void VisitUnit(Unit unit) 
        { 
            base.VisitUnit(unit); 
            UnitCount++; 
            if (unit as IPlayer) 
                VisitPlayerUnit(unit as IPlayer); 
        }
        public override void VisitPlayerUnit(IPlayer player) 
        { 
            AbilityEditor abilityEditor = player.AbilityEditor; 
            if (abilityEditor.CanPerform(UIInputObserver.CellGrid)) 
            { 
                UseableUnitCount++; 
            } 
            PlayerCount++; 
        }
        public void VisitorReset() 
        { 
            EnemyCount = 0; 
            UnitCount = 0; 
            UseableUnitCount = 0; 
        } 
    } 
}
IGameEventObserver.cs
namespace LinXuan.Common.GameEvent
{
    public interface IGameEventObserver
    {
        void SetSubject(IGameEventSubject subject);
        void ObserverUpdate();
    }
}
UnitUseAbilityObserverGUI.cs
using LinXuan.Common.GameEvent;
using TbsFramework.Grid;
namespace LinXuan.TBSF.GameEvent
{
    public class UnitUseAbilityObserverGUI : IGameEventObserver
    {
        private UseableUnitCountSubject m_UseableUnitCountSubject = null;
        private CellGrid m_CellGrid = null;
        public UnitUseAbilityObserverGUI(CellGrid cellGrid)
        {
            m_CellGrid = cellGrid;
        }
        public void ObserverUpdate()
        {
            m_CellGrid.UseableUnitCountGUIUpdate();
        }
        public void SetSubject(IGameEventSubject subject)
        {
            m_UseableUnitCountSubject = subject as UseableUnitCountSubject;
        }
    }
}
UseableUnitCountSubject.cs
namespace LinXuan.Common.GameEvent
{
    public class UseableUnitCountSubject : IGameEventSubject
    {
        public UnitCountEventArgs UnitCountEventArgs { get; private set; }
        public override void SetParameter(object parameter)
        {
            Notify();
        }
    }
}
CALWaitingForInputCellGridState.cs
using Assets.Scripts.GUI.GUITool;
using LuLuBearStudio.CALAbilities;
using System.Collections.Generic;
namespace Assets.Scripts.TBS_Framework_extends.CellGridStates
{
    public class CALWaitingForInputCellGridState : CellGridState
    {
        ...
        public override void OnStateEnter()
        {
            base.OnStateEnter();
            UIInputObserver.IsPlayerCanInput = true;
            foreach (Unit unit in units)
            {
                AbilityEditor abilityEditor = unit.GetComponent<AbilityEditor>();
                var canPerformAction = abilityEditor.CanPerform(_cellGrid);
                if (!canPerformAction)
                {
                    unit.SetState(new UnitStateMarkedAsFinished(unit));
                }
                else
                {
                    unit.SetState(new UnitStateNormal(unit));
                }
            }
UIInputObserver.CellGrid.NotifyGameEvent(LinXuan.TBSF.Enums.GameEventType.GetUseableUnitCount, null);
        }
        ...
    }
}
CellGrid.cs
public event EventHandler UseableUnitCountUpdate;
private UnitSystem m_UnitSystem;
private void Awake() 
{ 
    m_UnitSystem = new UnitSystem(this); 
}
private void Initialize() 
{
    ...
    m_UnitSystem.Initialize(Units);
}
public void RunUnitVisitor(IUnitVisitor unitVisitor) 
{ 
    m_UnitSystem.RunVisitor(unitVisitor); 
}
public void UseableUnitCountGUIUpdate()
{
    UseableUnitCountUpdate.Invoke(this, null);
}
CALGUIController.cs
private UnitInfoVisitor m_UnitInfoVisitor = new UnitInfoVisitor();
private void Awake() 
{ 
    CellGrid.UseableUnitCountUpdate += ShowUseableUnitCount;
}
private void Start()
{
    CellGrid.RegisterGameEvent(LinXuan.TBSF.Enums.GameEventType.GetUseableUnitCount, new UnitUseAbilityObserverGUI(UIInputObserver.CellGrid));
}
...
private void ShowUseableUnitCount(object sender, EventArgs e) 
{ 
    m_UnitInfoVisitor.VisitorReset(); 
    CellGrid.RunUnitVisitor(m_UnitInfoVisitor); 
    int useableCount = m_UnitInfoVisitor.UseableUnitCount; 
    Debug.Log("Useable count " + useableCount); 
}
這邊當角色還沒消耗完行動次數時,就會顯示可行動人數為兩人
而要是有單位消耗完行動次數後,數字就會相應減少
老實說寫起來有點繞一大圈的感覺,好處大概就是需要重新計算的時候在去做重新讀一次陣列的行為,不用每次都跑一次全部的陣列讀目前狀態,在陣列數量大的時候應該會更有感覺點
設計模式與遊戲開發的完美結合(暢銷回饋版)
Turn Based Strategy Framework
流離之歌